require "array"
require 'set'
module Filters
  class Not
    
    def initialize (pred)
      @pred = pred
    end
    
    def call(*data)
      ! @pred.call(*data)
    end
  end  
  
  class And 
    def initialize(*proc_array)
      @proc_array = proc_array
    end
    
    def call(data)
      @proc_array.each{|filter|
        return false unless filter.call(data)
      }
      return true
    end
  end
  
  class AllEven
    def call(numbers)
      numbers.each{|number|
        return false unless number.even?
      }
      return true
    end
  end
  
  class AllOdd
    def call(numbers)
      numbers.each{|number|
        return false if number.even?
      }
      return true
    end
  end
  
  def all_even
    AllEven.new
  end
  
  def all_odd
    AllOdd.new
  end
  
  
  def not_(filter)
    Not.new(filter)
  end
  
  
  class SumRange
    def initialize(range)
      @range=range
    end
    
    def call(numbers)
      return @range.include?(numbers.sum)
    end
  end
  
  class ContinuousLimit
    def initialize(max)
      @max = max
    end
    
    def call(numbers)
      for n in numbers
        for i in 1..@max + 1
          if numbers.include?(n+i)
            next
          else
            break
          end
        end
        return false if i == @max + 1
      end
      return true
    end
  end
  
  class RangeLimit
    def initialize(*ranges)
      @ranges = ranges
    end
    def call(numbers)
      numbersSet = numbers.to_set
      for range in @ranges
        rangeSet = range.to_a().to_set
        return false unless (numbersSet & rangeSet).size > 0
      end
      return true
    end
  end
  
  class PreviousLimit
    def initialize(history, max)
      @history = history
      @max = max
    end
    
    def call(numbers)
      for n in numbers
        for i in 1..@max + 1
          if @history[@history.length - i].include?(n)
            next
          else
            break
          end
        end
        return false if i == @max + 1
      end
      return true
    end
  end
  
  class LastLimit
    def initialize(history, max)
      @last = history[history.size - 1].to_set
      @max = max
    end
    
    def call(numbers)
      intersection = @last & numbers.to_set
      return intersection.length <= @max
    end
  end
  
end

